<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        /* Reflect对象的静态方法 */
        {
            let myObj = {
                foo: 1,
                bar: 2,
                [Symbol.for('sym')]: 555,
                get baz() { // 如果name属性部署了getter, 则读取函数的this绑定receiver
                    return this.foo + this.bar;
                },
                set tes(value) { // 如果name属性部署了setter, 则读取函数的this绑定receiver
                    return this.bar = value;
                }
            };
            let myReceiverObj = {
                foo: 3,
                bar: 4
            };

            /* get() - 查找属性 - Reflect.get(target, name, receiver) */
            console.log(Reflect.get(myObj, 'foo'));
            console.log(Reflect.get(myObj, 'baz', myReceiverObj)); // 7 

            /* set() - 设置属性 - Reflect.set(target, name, value, receiver) */
            Reflect.set(myObj, 'foo', 11);
            console.log(myObj.foo);
            Reflect.set(myObj, 'bar', 0, myReceiverObj); // 如果name属性部署了getter, 则读取函数的this绑定receiver
            console.log(myReceiverObj.bar);

            /* has() - in操作符 - Reflect.has(obj, name) */
            console.log(Reflect.has(myObj, 'foo'));

            /* deleteProperty() - 删除属性 - Reflect.deleteProperty(obj, name) */
            Reflect.deleteProperty(myObj, 'foo'); // 返回值true
            console.log(myObj.foo); // undefined

            /* construct() - new操作符 - Reflect.construct(target, args) */
            const Person = function (name) { this.name = name; };
            const p = Reflect.construct(Person, ['papa']); // 不用new调用构造函数
            console.log(p);

            /* getPrototypeOf() - 读取__proto__ - Reflect.getPrototypeOf(obj) */
            console.log(Reflect.getPrototypeOf(p) === Person.prototype); // true

            /* setPrototypeOf() - 设置prototype - Reflect.setPrototypeOf(obj, newProto) */
            const proto = {};
            Reflect.setPrototypeOf(p, proto);
            console.log(Reflect.getPrototypeOf(p) === Person.prototype, Reflect.getPrototypeOf(p) === proto); // false true

            /* apply() - 等同于Function.prototype.apply.call(fn, obj, args) - Reflect.apply(func, thisArg, args) */
            const ages = [11, 33, 12, 54, 18, 96];
            // const youngest = Math.min.apply(Math, ages); // 旧写法
            const youngest = Reflect.apply(Math.min, Math, ages);
            console.log(youngest);

            /* defineProperty() - 为对象定义属性 - Reflect.defineProperty(target, propertyKey, attributes) */
            let MyDate = function () { };
            // 旧写法
            Object.defineProperty(MyDate, 'now', {
                value: () => Date.now()
            });
            // 新写法
            Reflect.defineProperty(MyDate, 'now', {
                value: () => Date.now()
            });

            /* getOwnPropertyDescriptor() - 获取描述对象 - Reflect.getOwnPropertyDescriptor(target, propertyKey) */
            console.log(Reflect.getOwnPropertyDescriptor(myObj, 'bar'));

            /* isExtensible() - 对象是否可扩展 - Reflect.isExtensible (target) */
            console.log(Reflect.isExtensible(myObj)); // true
            // console.log(Reflect.isExtensible(1)); // 报错

            /* preventExtensions() - 使对象不可扩展 - Reflect.preventExtensions(target) */
            Reflect.preventExtensions(myObj);
            console.log(Reflect.isExtensible(myObj)); // false

            /* ownKeys() - 返回对象所有属性(包括symbol属性名) - Reflect.ownKeys (target) */
            // Object.getOwnPropertyNames与Object.getOwnPropertySymbols的结合
            console.log(Reflect.ownKeys(myObj));
        }

        /* Proxy实现观察者模式 - 函数自动观察数据对象, 一旦对象有变化，函数就会自动执行 */
        {
            const queuedObservers = new Set();

            const observe = fn => queuedObservers.add(fn);
            const observable = obj => new Proxy(obj, { set });

            function set(target, key, value, receiver) {
                const result = Reflect.set(target, key, value, receiver);
                queuedObservers.forEach(observer => observer());
                return result;
            }
        }
    </script>
</body>

</html>